import pandas as pd
import plotly.express as px
import plotly.graph_objs as go
from plotly.subplots import make_subplots
import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np
import scipy.stats as stats
from sklearn.preprocessing import MinMaxScaler, StandardScaler, RobustScaler
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error, r2_score
from sklearn.linear_model import LinearRegression
from sklearn.neighbors import KNeighborsRegressor
from sklearn.svm import SVR
from sklearn.ensemble import RandomForestRegressor
import warnings
warnings.filterwarnings('ignore')
ventes = pd.read_csv(
"https://raw.githubusercontent.com/murpi/wilddata/master/test/history.csv")
bordeaux = pd.read_csv(
"https://raw.githubusercontent.com/murpi/wilddata/master/test/bordeaux2019.csv",
skiprows=3)
lille = pd.read_csv(
"https://raw.githubusercontent.com/murpi/wilddata/master/test/lille2019.csv",
skiprows=3)
lyon = pd.read_csv(
"https://raw.githubusercontent.com/murpi/wilddata/master/test/lyon2019.csv",
skiprows=3)
marseille = pd.read_csv(
"https://raw.githubusercontent.com/murpi/wilddata/master/test/marseille2019.csv",
skiprows=3)
prev_meteo_fin_juin = pd.read_csv(
"https://raw.githubusercontent.com/murpi/wilddata/master/test/forecast.csv"
)
Nous analyserons les données de vente du DataFrame ventes en vérifiant tout d'abord s'il y a des données manquantes et si le Dtype pour chaque variable est correct. Nous observerons par la suite comment les ventes des différents produits varient au cours de l'année.
On vérifie avec la méthode info():
ventes.info()
Résultat: la variable DATE affiche un Dtype object, il convient de transtyper cette variable en datetime. Sur les 520 entrées aucunes données nous sont retournées nulles.
La méthode .duplicated() nous retourne pour toutes les lignes si des doublons sont présents par des valeurs booléennes: True ou False. Si on ajoute la méthode .unique() nous agrégerons la réponse en vérifant si les 2 valeurs nous sont ou non retournées.
Si:
print(ventes.duplicated().unique())
Pour faciliter notre analyse nous utiliserons la fonction pd.to_datetime() pour transtyper la variable en datetime.
# Transtypage object en datetime
ventes["DATE"] = pd.to_datetime(ventes["DATE"], format="%d-%m-%Y")
Pour observer la saisonnalité des ventes, nous allons classer les ventes par mois et par produits vendus grâce à la fonction plot_saisonnalite_ventes().
Dans un premier temps, pour faciliter notre analyse, nous utiliserons la fonction pd.to_datetime() pour transtyper la variable en datetime. On utilisera la méthode dt.strftime() pour formater la colonne de dates en mois avec l'argument "%m". Une fois notre colonne MOIS créée, nous l'utiliserons à la place de DATE et regrouperons par mois les ventes totales (SALES) par groupe de produits (ITEM).
Afin de mieux observer et analyser l'évolution des ventes selon les produits, nous utiliserons la libraire Plotly pour créer un graphique à barres ou un graphique utilisant des lignes. Ce dernier graphique nous permettra de vérifier la corrélation entre les ventes et les données météoroliques.
def plot_saisonnalite_ventes(df, viz="bar"):
"""
Cette fonction prend en entrée un dataframe "df" contenant les données
de ventes et un argument optionnel "viz" qui permet de choisir entre
un graphique à barres ou un graphique avec des lignes pour visualiser
la saisonnalité des ventes.
Par défaut, la visualisation est réalisée avec un graphique à barres.
Dependencies:
- pandas
- plotly
Parameters:
df (DataFrame): Dataframe contenant les données de ventes
viz (str): Type de visualisation souhaitée. "bar" pour un graphique à
barres ou "line" pour un graphique avec des lignes.
Returns:
Graphique de la saisonnalité des ventes pour chaque produit, soit sous
forme de graphique à barres ou de graphique avec des lignes.
"""
# On crée une nouvelle colonne "MOIS" pour regrouper les ventes par mois
df["MOIS"] = df["DATE"].dt.strftime("%m")
# On agrège les ventes par mois pour chaque produit
df = df.groupby(["MOIS", "ITEM"], as_index=False)["SALES"].sum()
# On crée le graphique de la saisonnalité des ventes
# On retourne un graphique à barres par défaut...
if viz == "bar":
fig = px.bar(df,
x="MOIS",
y="SALES",
color="ITEM",
barmode="group",
title="<b>Saisonalité des ventes</b>",
text_auto=True,
height=600,
width=980)
fig.update_layout(bargap=0.2,
title_x=0.5,
yaxis_title="Chiffre d'affaires (en €)")
# ... ou un graphique à lignes si viz="line"
elif viz == "line":
fig = px.line(df,
x="MOIS",
y="SALES",
color="ITEM",
title="<b>Saisonalité des ventes</b>",
height=600,
width=980)
# On ajoute un marqueur par mois sur chaque ligne
for trace in fig.data:
trace.update(mode="lines+markers")
fig.update_layout(title_x=0.5, yaxis_title="Chiffre d'affaires (en €)")
# Un message d'erreur si viz != de "bar" ou "line"
else:
print("Erreur: l'argument viz doit être 'bar' ou 'line'.")
return
fig.show()
plot_saisonnalite_ventes(ventes)
plot_saisonnalite_ventes(ventes, viz="line")
Les ventes semble être corrélées à la météo. Dans ce contexte pour déterminer à quelle boutique le fichier ventes correspond, nous analyserons les données météo des boutiques situées à Bordeaux, Lille, Lyon, et Marseille.
Note: Afin d'intégrer une nouvelle ville à l'analyse, nous créerons une fonction automatisant la création d'un dataframe
bordeaux.info()
Nous créerons une fonction qui nous permettra d'afficher une heatmap de la matrice des corrélations.
La fonction corr() de Pandas sera utilisé pour trouver la corrélation par paire de toutes les colonnes de la trame de données. Nous rajouterons un argument method pour utiliser la méthode de Spearman lorsque les données ne seront pas normalisées.
Nous créerons un mask avec zeros_like() de NumPy pour renvoyer un tableau de formes et de tailles similaires avec les valeurs des éléments du tableau remplacées par des zéros. Dans ce même package, nous utiliserons aussi la fonction triu_indices_from() pour obtenir une copie des éléments d'un tableau.
Pour produire l'heatmap nous utiliserons le package Seaborn possédant dans ses arguments la possibilité d'inclure notre mask.
Nous concaténerons les données météo pour chaque ville dans un même dataframe: meteo.
Dans un nouveau DataFrame data, nous joindrons les deux dataframes ventes et meteo sur la colonne DATE afin de vérifier quelles sont les variables météorologiques les plus corrélées aux ventes d'ITEM.
def display_matrice_corr(df, method="pearson"):
"""
Fonction d'analyse visuelle qui illustre la corrélation par
paire de toutes les colonnes de la trame de données.
Dependencies:
- seaborn
- matplotlib
Arguments :
df (DataFrame): Dataframe contenant les variables à corréler.
method (str) : Méthode utilisée pour calculer les corrélations. Les options sont "pearson" (par défaut) et "spearman".
Returns:
Heatmap de la matrice des corrélations.
"""
# Calcul de la matrice de corrélation
if method == "spearman":
corr = df.corr(method="spearman")
else:
corr = df.corr()
# Création du mask
mask = np.zeros_like(corr)
triangle_indices = np.triu_indices_from(mask)
mask[triangle_indices] = True
# Visualisation de la matrice en heatmap
with sns.axes_style("white"):
plt.figure(figsize=(16, 10))
sns.heatmap(corr.round(2),
mask=mask,
annot=True,
annot_kws={"size": 13},
cmap="RdYlBu",
linewidths=1)
plt.xticks(fontsize=14, rotation=90)
plt.yticks(fontsize=14, rotation=0)
plt.title("Matrice de corrélation", size=24)
# On concatène les données météo pour chaque ville dans un même dataframe
meteo = pd.concat([bordeaux, lille, lyon, marseille], ignore_index=True)
# On converti la colonne "DATE" en format datetime pour les deux dataframes
ventes["DATE"] = pd.to_datetime(ventes["DATE"])
meteo["DATE"] = pd.to_datetime(meteo["DATE"])
# On joint les deux dataframes sur la colonne "DATE"
data = pd.merge(ventes, meteo, on="DATE", how="inner")
# Nos données ne sont pas normalisées, nous utiliserons la méthode de Spearman
display_matrice_corr(data, method="spearman")
Les coefficients de corrélation renvoient la force et le sens de la relation linéaire entre deux variables. Un coefficient de corrélation de 1 indique une relation parfaitement positive linéaire, c'est-à-dire que les variables augmentent ensemble.
Un coefficient de corrélation de -1 indique une relation parfaitement négative linéaire, c'est-à-dire que l'une des variables augmente tandis que l'autre diminue. Un coefficient de corrélation de 0 indique que les variables ne sont pas liées.
D'après les résultats obtenus, il y a une très faible corrélation positive entre la température maximale (TEMPERATURE_MAX) et les ventes (coefficient de corrélation de 0.07).
Il n'y a pas de corrélation significative entre la vitesse maximale du vent (WINDSPEED_MAX_KMH) et les ventes (coefficient de corrélation de -0.04) ou entre les précipitations totales (PRECIP_TOTAL_DAY_MM) et les ventes (coefficient de corrélation de -0.04).
Il y a une faible corrélation positive entre la température du vent (WINDTEMP_MAX_C) et les ventes (coefficient de corrélation de 0.07) et pas de corrélation significative entre la couverture nuageuse (CLOUDCOVER_AVG_PERCENT) et les ventes (coefficient de corrélation de -0.04).
Note: ces résultats ne prouvent pas une causalité entre les variables, mais seulement une corrélation. Il est possible qu'il y ait d'autres facteurs qui influencent les ventes et qu'il faut prendre en compte pour une analyse plus complète.
Même si sur l'ensemble des ventes une faible corrélation existe entre certaines données météorologiques, il serait intéressant de vérifier si une corrélation semble plus forte selon le produit vendu.
Pour rappel, lors de l'analyse de la saisonnalité des ventes (Voir chapître 4.2 Saisonnalité des ventes), nous avions pu observer un net écart entre les mois de mai et octobre (tous deux inclus) où le CA des produits B est plus fort. A l'inverse le CA des produits A est plus fort entre novembre et janvier inclus.
Grâce à la fonction merge() de Pandas, nous créerons une fonction qui fusionnera les données de ventes et de météo sur la colonne DATA.
Avec la libraire scipy.stats nous calculerons le coefficielent de corrélation entre les ventes générales, ainsi que les ventes par ITEM, avec les variables météorologiques de température maximale, vitesse maximale du vent et précipitations totales et renvoie un tableau des corrélations
def correlation_ventes_meteo(ventes, meteo, method="pearson"):
"""
Cette fonction prend en entrée un dataframe "ventes" contenant les données
de ventes et un dataframe "meteo" contenant les données météorologiques.
Elle calcule les coefficients de corrélation entre les ventes et les
variables météorologiques de température maximale, vitesse maximale du
vent et précipitations totales et renvoie un tableau des corrélations.
Dependencies:
- pandas
- scipy.stats
Parameters:
ventes (DataFrame): Dataframe contenant les données de ventes.
meteo (DataFrame): Dataframe contenant les données météorologiques.
Returns:
Dataframe contenant les coefficients de corrélation.
"""
# On fusionne les données ventes et météo sur la colonne "DATE"
data = pd.merge(ventes, meteo, on="DATE")
# On crée un dictionnaire pour stocker les coefficients de corrélation
corr = {}
# Calcul de la matrice de corrélation
if method == "spearman":
corr_func = stats.spearmanr
else:
corr_func = stats.pearsonr
# On calcule les coefficients de corrélation entre les ventes
# et les variables météorologiques
corr["TEMPERATURE_MAX"] = corr_func(data["SALES"],
data["MAX_TEMPERATURE_C"])[0]
corr["VITESSE_MAX"] = corr_func(data["SALES"],
data["WINDSPEED_MAX_KMH"])[0]
corr["COUVERTURE_NUAGEUSE"] = corr_func(data["SALES"],
data["CLOUDCOVER_AVG_PERCENT"])[0]
items = data['ITEM'].unique()
for item in items:
corr[f"TEMPERATURE_MAX_{item}"] = corr_func(
data[data["ITEM"] == item]["SALES"],
data[data["ITEM"] == item]["MAX_TEMPERATURE_C"])[0]
corr[f"VITESSE_MAX_{item}"] = corr_func(
data[data["ITEM"] == item]["SALES"],
data[data["ITEM"] == item]["WINDSPEED_MAX_KMH"])[0]
corr[f"COUVERTURE_NUAGEUSE_{item}"] = corr_func(
data[data["ITEM"] == item]["SALES"],
data[data["ITEM"] == item]["CLOUDCOVER_AVG_PERCENT"])[0]
# On crée un tableau des corrélations
corr_table = pd.DataFrame.from_dict(corr,
orient="index",
columns=["Coefficient de corrélation"])
# Calcul de la matrice de corrélation pour toutes les colonnes du dataframe
corr = data.corr()
return corr_table.round(2)
Nous créerons une fonction pour vérifier l'évolution des données météos pour la ville donnée selon les variables les plus corrélées au fichier ventes.
Dans un premier temps, pour coller avec la saisonnalité de notre fichier ventes, nous agrégerons la variable DATE selon le mois.
Afin de faciliter l'analyse météorologique, nous pouvons limiter le nombre de variable à 4:
def plot_evo_mensuel_meteo(df, ville):
"""
Cette fonction prend en entrée un dataframe 'df' et un nom de ville
'ville' et renvoie un graphique représentant l'évolution mensuelle des
données météorologiques pour la ville donnée. Les données météorologiques
étudiées sont: la température maximale en degré celsius, la vitesse
maximale du vent en km/h et la couverture nuageuse moyenne.
Dependencies:
- pandas
- plotly
Parameters:
df (DataFrame): Dataframe contenant les données météorologiques.
ville (str): Nom de la ville pour laquelle les données météorologiques
sont étudiées.
Returns:
Graphique de l'évolution mensuelle des données météorologiques pour
la ville donnée.
"""
# On convertit la colonne "DATE" en format date
# errors="coerce" permet de forcer la conversion des valeurs en NaT
df["DATE"] = pd.to_datetime(df["DATE"], errors="coerce")
# On supprime les lignes contenant des valeurs manquantes pour "DATE"
df = df.dropna(subset=["DATE"])
# On crée une nouvelle colonne 'MOIS' pour regrouper les données
# météorologiques par mois
df["MOIS"] = df["DATE"].dt.strftime("%m")
# On groupe les données météorologiques par mois pour la ville donnée
result = df.groupby("MOIS")[[
"MAX_TEMPERATURE_C", "WINDSPEED_MAX_KMH", "CLOUDCOVER_AVG_PERCENT"
]].mean().round(2)
# On crée le graphique de l'évolution mensuelle des données météorologiques
fig = go.Figure()
fig.add_trace(
go.Scatter(x=result.index,
y=result["MAX_TEMPERATURE_C"],
mode="lines+markers",
name="Température max en C°"))
fig.add_trace(
go.Scatter(x=result.index,
y=result["WINDSPEED_MAX_KMH"],
mode="lines+markers",
name="Vitesse max en KM/H"))
fig.add_trace(
go.Scatter(x=result.index,
y=result["CLOUDCOVER_AVG_PERCENT"],
mode="lines+markers",
name="Couverture nuageuse moyenne"))
fig.update_layout(
xaxis_title="Mois",
yaxis_title="Mesures météorologiques en moyennes",
title=
f"<b>Evolution mensuelle des données météorologiques pour la ville de {ville}</b>"
)
fig.show()
plot_evo_mensuel_meteo(bordeaux, "Bordeaux")
correlation_ventes_meteo(ventes, bordeaux, method="spearman")
plot_evo_mensuel_meteo(lille, "Lille")
correlation_ventes_meteo(ventes, lille, method="spearman")
plot_evo_mensuel_meteo(lyon, "Lyon")
correlation_ventes_meteo(ventes, lyon, method="spearman")
plot_evo_mensuel_meteo(marseille, "Marseille")
correlation_ventes_meteo(ventes, marseille, method="spearman")
Il semble que la ville avec les données météorologiques les plus corrélées aux ventes pour les items A et B soit Bordeaux.
En effet, la corrélation entre les ventes et les variables météorologiques pour cette ville est plus élevée que pour les autres villes.
Cependant, il est important de noter que ces coefficients de corrélation sont faibles et ne permettent pas de tirer des conclusions définitives sur les relations entre les données météorologiques et les ventes.
Note: ces résultats ne prouvent pas une causalité entre les variables, mais seulement une corrélation. Il est possible qu'il y ait d'autres facteurs qui influencent les ventes et qu'il faut prendre en compte pour une analyse plus complète.
# On concatène les données météo pour chaque ville dans un même dataframe
meteo = pd.concat([bordeaux, lille, lyon, marseille], ignore_index=True)
correlation_ventes_meteo(ventes, meteo, method="spearman")
plot_saisonnalite_ventes(ventes, viz="line")
La température semble être la variable météorologique la plus impactante concernant les ventes.
D'après les résultats obtenus:
Note: ces résultats ne prouvent pas une causalité entre les variables, mais seulement une corrélation. Il est possible qu'il y ait d'autres facteurs qui influencent les ventes et qu'il faut prendre en compte pour une analyse plus complète.
prev_meteo_fin_juin.info()
Pour réaliser notre prédiction, nous utiliserons une régression linéaire multiple avec une méthode pas-à-pas descendant (stepwise). Cette procédure itérative nous permettra d'optimiser nos modèles en nous donnant la possibilité d'éliminer les variables devenues non significatives.
Nous trouverons le modèle le plus parcimonieux (en minimisant AIC) avec un ($R^{2}$) et un F-stat important.
Nous diviserons le process en différentes étapes:
la préparation du dataset de prédiction, nous devrons merger les dataframes ventes et bordeaux (qui correspond à notre boutique, voir chapître 5.5 Résultat concernant la boutique) en nous basant sur la variable DATE.
Nous n'utiliserons que les variables communes avec le dataframe prev_meteo_fin_juin. Pour cela nous utiliserons la méthode intersection(), nous copierons le résultat dans un nouveau dataframe ventes_bordeaux_predict. La temporalité n'étant pas la même entre prev_meteo_fin_juin et ventes_bordeaux, nous supprimerons la variable DATE;
le feature scaling des données, nos données météorologiques ayant des unités différentes de mesures entre elles il conviendra de les centrer-réduire. Le principal avantage de la centration-réduction est de rendre comparables des variables qui ne le seraient pas directement parce qu'elles ont des moyennes et ou des variances trop différentes. Les fonctions de feature scaling sont regroupées dans le package preprocessing de Sklearn;
puisque l'impact des données météos changent selon l'item nous séparerons notre jeu de donnée par item. Nous utiliserons la fonction *loc() de Pandas;
# On réalise notre jointure
ventes_bordeaux = pd.merge(ventes, bordeaux, on="DATE", how="left")
# On sélectionne les variables en commun entre les deux dataframes en
# excluant la colonne "DATE"
common_vars = list(
set(ventes_bordeaux.columns).intersection(
prev_meteo_fin_juin.columns.difference(["DATE"])))
# On conserve seulement les variables en commun et la colonne "ITEM"
# dans ventes_bordeaux
ventes_bordeaux_predict = ventes_bordeaux[["SALES", "ITEM"] + common_vars]
Nous allons normaliser ici uniquement les variables météorologiques, nous n'incluerons donc pas DATE et ITEM dans la trasnformation des données.
Afin d'améliorer les performances de notre algorithme de prédiction nous traiterons chaque variable de manière optimale. Pour cela nous créerons une fonction qui utilisera l'une des méthodes de sklearn.preprocessing comme MinMaxScaler, StandardScaler ou RobustScaler.
def normalize_ventes_meteo(df):
"""
Cette fonction prend en entrée un dataframe (df) et retourne ce même
dataframe après avoir normalisé toutes les colonnes sauf "SALES" et "ITEM".
La méthode de normalisation utilisée dépend de la distribution des
données de chaque colonne:
- Si la colonne a une forte asymétrie (skewness > 0.75),
la méthode utilisée est RobustScaler
- Si la colonne a une forte Kurtosis (kurtosis > 3),
la méthode utilisée est StandardScaler
- Sinon, la méthode utilisée est MinMaxScaler
Dependencies:
- pandas
- sklearn.preprocessing (MinMaxScaler, StandardScaler, RobustScaler)
Parameters:
- df (Dataframe): Dataframe contenant les variables météo à normaliser.
Returns:
- df (Dataframe): Dataframe contenant les variables météo normalisées.
"""
columns_to_normalize = [
col for col in df.columns if col not in ["SALES", "ITEM"]
]
for col in columns_to_normalize:
if df[col].skew() > 0.75:
scaler = RobustScaler()
elif df[col].kurtosis() > 3:
scaler = StandardScaler()
else:
scaler = MinMaxScaler()
df.loc[:, col] = scaler.fit_transform(df[[col]])
return df
ventes_bordeaux_predict_normalize = normalize_ventes_meteo(
ventes_bordeaux_predict)
# Uniquement les items A
ventes_bordeaux_predict_normalize_A = ventes_bordeaux_predict_normalize.loc[
ventes_bordeaux_predict_normalize["ITEM"] == "A"]
# Uniquement les items B
ventes_bordeaux_predict_normalize_B = ventes_bordeaux_predict_normalize.loc[
ventes_bordeaux_predict_normalize["ITEM"] == "B"]
Nous testerons ici sur nos deux jeux de données ventes_bordeaux_predict_normalize_A et ventes_bordeaux_predict_normalize_B quel algorithme nous permettrait d'obtenir la meilleure prédiction.
Nous créerons une fonction pour tester 4 algorithmes:
LinearRegression, est un modèle de régression linéaire simple qui prédit la variable cible en utilisant une combinaison linéaire des variables indépendantes. Il permet d'estimer les coefficients de régression et de prévoir les valeurs de la variable cible;
KNeighborsRegressor, est un modèle de régression basé sur l'algorithme des k plus proches voisins. Il prédit la valeur cible en utilisant les valeurs cibles des k observations les plus proches de la nouvelle observation. Il est souvent utilisé pour des tâches de regression non linéaires;
SVR, est un modèle de régression basé sur les machines à vecteurs de support. Il est utilisé pour résoudre des problèmes de régression dans lesquels les relations entre les variables indépendantes et dépendantes sont non linéaires. Il peut être utilisé avec différents types de noyaux pour résoudre des problèmes de régression non linéaires;
RandomForestRegressor, est un modèle de régression basé sur l'algorithme de forêt aléatoire. Il construit plusieurs arbres de décision et utilise la moyenne des prédictions de ces arbres pour prévoir la variable cible. Il est souvent utilisé pour des tâches de régression non linéaires et peut également être utilisé pour sélectionner des variables importantes.
Pour interpréter ces résultats nous utiliserons deux indicateurs:
def test_algorithms(df):
"""
Cette fonction prend en entrée un dataframe (df) et teste différents
modèles de régression sur les données contenues dans ce dataframe. Les
modèles utilisés sont Linear Regression, KNN, SVM et Random Forest. Les
données sont divisées en données d'entraînement et de test avant d'être
utilisées. Les résultats de chaque modèle sont affichés sous la forme d'un
score MSE et d'un score R2.
Dependencies:
- pandas
- sklearn.model_selection (train_test_split)
- sklearn.metrics (mean_squared_error, r2_score)
- sklearn.linear_model (LinearRegression)
- sklearn.neighbors (KNeighborsRegressor)
- sklearn.svm (SVR)
- sklearn.ensemble (RandomForestRegressor)
Parameters:
- dataframe (Dataframe): Dataframe contenant les données à utiliser pour
entraîner les modèles.
Returns:
- None. Affiche les résultats de l'évaluation des différents modèles de
régression: mean squared error (MSE) et coefficient de détermination (R2)
pour chaque modèle.
"""
# On sélectionne les variables météo
meteo_vars = [
"MAX_TEMPERATURE_C", "WINDSPEED_MAX_KMH", "CLOUDCOVER_AVG_PERCENT",
"HUMIDITY_MAX_PERCENT", "MIN_TEMPERATURE_C", "PRECIP_TOTAL_DAY_MM",
"VISIBILITY_AVG_KM", "PRESSURE_MAX_MB"
]
# On sépare les données en données d'entraînement et de test
X_train, X_test, y_train, y_test = train_test_split(df[meteo_vars],
df["SALES"],
test_size=0.2)
# On entraîne différents modèles de régression
models = {
'Linear Regression': LinearRegression(),
'KNN': KNeighborsRegressor(),
'SVM': SVR(),
'Random Forest': RandomForestRegressor()
}
# On évalue chaque modèle sur les données de test
for name, model in models.items():
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
print(
f"{name} MSE: {mean_squared_error(y_test, y_pred).round(2)} R2: {r2_score(y_test, y_pred).round(2)}"
)
test_algorithms(ventes_bordeaux_predict_normalize_A)
test_algorithms(ventes_bordeaux_predict_normalize_B)
Le Random Forest a un $R^{2}$ proche de 1 pour les deux jeux de données, (0.93 pour les items A et 0.94 pour les items B) ce qui indique que les prédictions sont très proches des valeurs réelles. Il est donc un bon choix pour prédire les ventes en fonction des variables météo. De plus leur MSE est aussi le plus proche de 0 (9.71 pour les items A et 239.88 pour les items B) nous donnant la meilleure performance de prédiction.
# Variable dépendante pour les items A
y_a = ventes_bordeaux_predict_normalize_A["SALES"]
# Variable dépendante pour les items B
y_b = ventes_bordeaux_predict_normalize_B["SALES"]
# Variables météos
meteo_vars = [
"MAX_TEMPERATURE_C", "WINDSPEED_MAX_KMH", "CLOUDCOVER_AVG_PERCENT",
"HUMIDITY_MAX_PERCENT", "MIN_TEMPERATURE_C", "PRECIP_TOTAL_DAY_MM",
"VISIBILITY_AVG_KM", "PRESSURE_MAX_MB"
]
# Variables explicatives quantitatives pour les items A
X_a = ventes_bordeaux_predict_normalize_A[meteo_vars]
# Variables explicatives quantitatives pour les items A
X_b = ventes_bordeaux_predict_normalize_B[meteo_vars]
# Pour les items A
X_a_train, X_a_test, y_a_train, y_a_test = train_test_split(X_a,
y_a,
train_size=0.8,
random_state=42)
# Pour les items B
X_b_train, X_b_test, y_b_train, y_b_test = train_test_split(X_b,
y_b,
train_size=0.8,
random_state=42)
def create_random_forest_model(X_train, y_train):
"""
Cette fonction prend en entrée des données d'entraînement (X_train, y_train)
et retourne un modèle de prédiction utilisant l'algorithme RandomForestRegressor.
Dependencies:
- sklearn.ensemble (RandomForestRegressor)
Parameters:
- X_train (DataFrame): Dataframe contenant les variables explicatives
pour les données d'entraînement
- y_train (Series): Series contenant les variables dépendantes pour
les données d'entraînement
Returns:
- model (RandomForestRegressor): modèle de prédiction utilisant
l'algorithme RandomForestRegressor
"""
model = RandomForestRegressor(random_state=42)
model.fit(X_train, y_train)
return model
# Pour les item A
model_a = create_random_forest_model(X_a_train, y_a_train)
# Pour les item
model_b = create_random_forest_model(X_b_train, y_b_train)
# Prédictions pour les items A
y_a_pred = model_a.predict(X_a_test)
# Prédictions pour les items B
y_b_pred = model_b.predict(X_b_test)
# Évaluation du modèle pour les items A
print(
f"Item A - MSE : {mean_squared_error(y_a_test, y_a_pred).round(2)}, R2 : {r2_score(y_a_test, y_a_pred).round(2)}"
)
# Évaluation du modèle pour les items B
print(
f"Item B - MSE : {mean_squared_error(y_b_test, y_b_pred).round(2)}, R2 : {r2_score(y_b_test, y_b_pred).round(2)}"
)
A la vue des résultats notre modèle de prédiction semble être très précis.
prev_meteo_fin_juin["STOCK_A"] = model_a.predict(
normalize_ventes_meteo(prev_meteo_fin_juin[meteo_vars])).round()
prev_meteo_fin_juin["STOCK_B"] = model_b.predict(
normalize_ventes_meteo(prev_meteo_fin_juin[meteo_vars])).round()
prev_meteo_fin_juin
Nous comparerons ici l'évolution des prévisions météorologiques de la semaine du 21 au 27 juin avec les stocks à prévoir pour les items A et B.
def plot_stock_evolution(df, meteo_vars):
"""
Cette fonction permet de visualiser l'évolution des stocks
A et B en fonction de la date et de plusieurs variables
météorologiques. Il crée un sous-graphe pour chaque variable
météo, ajoute les tracés pour chaque variable météo et pour
les stocks A et B, met à jour les titres des axes x et y et
affiche le graphe.
Dependencies:
- Plotly.graph_objs
- Plotly.subplots
Parameters:
- df (DataFrame): Le DataFrame contenant les données à
visualiser
- meteo_vars (list): La liste des variables météorologiques
à inclure dans le graphe
Returns:
Subplot de l'évolution des stocks A et B et des donnés météos
"""
# On crée un sous-graphe pour chaque variable météo
fig = make_subplots(rows=len(meteo_vars) + 1,
cols=1,
shared_xaxes=True,
vertical_spacing=0.1)
# On ajoute les tracés pour chaque variable météo
for i, var in enumerate(meteo_vars):
fig.add_trace(go.Scatter(x=df["DATE"],
y=df[var],
name=var,
mode="lines+markers"),
row=i + 1,
col=1)
# On ajoute les tracés pour STOCK_A et STOCK_B
fig.add_trace(go.Scatter(x=df['DATE'],
y=df['STOCK_A'],
name='STOCK_A',
mode='lines+markers'),
row=len(meteo_vars) + 1,
col=1)
fig.add_trace(go.Scatter(x=df['DATE'],
y=df['STOCK_B'],
name='STOCK_B',
mode='lines+markers'),
row=len(meteo_vars) + 1,
col=1)
# On met à jour les titres de l'axe x et y
fig.update_layout(
title=f"<b>Prévision des stocks et des données météos</b>")
# On affiche le graphe
fig.show()
# Variables météos
meteo_vars = ["MAX_TEMPERATURE_C", "CLOUDCOVER_AVG_PERCENT"]
plot_stock_evolution(prev_meteo_fin_juin, meteo_vars)
On observe bien une corrélation entre la hausse des températures et l'augmentation du stock de produits B, à l'inverse lorsque la couverture nuageuse arrive, annonçant la pluie, les stock des produits A augmente.